import logging
import os
import urllib
import base64
import urlparse
import cgi

import config

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.ext import db
from google.appengine.api import urlfetch
from google.appengine.ext import ereporter

ereporter.register_logger()


class Runner(db.Model):
  waiver_version = db.StringProperty(required=True)
  age = db.IntegerProperty()
  gender = db.StringProperty()


class MainPage(webapp.RequestHandler):

  mode = 'sandbox'
  conf = config.Config(mode)

  def render_page(self, errors=None):
    template_values = { 'merchant_id': self.conf.merchant_id,
                        'errors': errors }
    path = os.path.join(os.path.dirname(__file__), 'form.html')
    self.response.out.write(template.render(path, template_values))

  def render_error_page(self):
    template_values = {}
    path = os.path.join(os.path.dirname(__file__), 'error.html')
    self.response.out.write(template.render(path, template_values))

  def get(self):
    self.render_page()

  def get_form_data(self):
    form_fields = {
      '_type': 'checkout-shopping-cart',
      'item_name_1': 'Mad Dash registration',
      'item_description_1': 'Registration for one runner/walker for Mad Dash on October 27 2012 at the Polo Fields in Golden Gate Park.',
      'item_price_1': '30.00',
      'item_currency_1': 'USD',
      'item_quantity_1': '1',
      'item_merchant_id_1': self.conf.merchant_id }
    return urllib.urlencode(form_fields)

  def get_request_headers(self, authorization_key):
    headers = { 'Authorization': 'Basic ' + authorization_key,
                'Content-Type': 'application/x-www-form-urlencoded',
                'Accept': 'application/xml;charset=UTF-8', }
    return headers

  def run_urlfetch(self, url, form_data, headers):
    return urlfetch.fetch(url=url,
                          payload=form_data,
                          method=urlfetch.POST,
                          headers=headers)
  
  def get_checkout_redirect(self):
    url = self.conf.checkout_url + self.conf.merchant_id
    form_data = self.get_form_data()
    authorization_key = base64.b64encode(self.conf.merchant_id + ':' + self.conf.merchant_key)
    headers = self.get_request_headers(authorization_key)
    try:
      while True:
        timeout_ms = 100
        try:
          fetch_result = self.run_urlfetch(url, form_data, headers)
          break
        except urlfetch.DownloadError:
          logging.exception('problem running urlfetch')
          thread.sleep(timeout_ms)
          timeout_ms *= 2
    except:
      # Ran out of retries, probably due to a request deadline exceeded
      # display an error message to the user
      logging.exception('urlfetch did not complete')
      # this does not work....
      self.render_error_page()
      return

    if fetch_result.status_code == 200:
      result = cgi.parse_qs(fetch_result.content)
      # parse_qs requires python 2.7
      # result = urlparse.parse_qs(fetch_result.content)
      if result.has_key('_type'):
        if result['_type'][0] == 'checkout-redirect':
          return result['redirect-url'][0]
        else:
          logging.error('Not redirect: %s' % fetch_result.content)
      else:
        logging.error('No _type: %s' % fetch_result.content)
    else:
      logging.error('Status %d with result: %s' % (fetch_result.status_code, fetch_result.content))

  def post(self):
    # process form if waive is signed
    if self.request.get('waiver', default_value='') == 'signed':
      # handle the form input
      age = self.request.get('age', default_value='')
      try:
        age_int = int(age)
      except ValueError:
        age_int = 0
      # insert into the datastore
      runner = Runner(waiver_version=self.request.get('waiver_version', default_value='unknown'), 
                      age=age_int, gender=self.request.get('gender', default_value=''))
      try:
        runner_key = runner.put()
      except (db.Timeout, db.InternalError):
        logging.exception('Runner not written')
      # redirect to checkout
      url = self.get_checkout_redirect()
      self.redirect(url)
    # form had errors
    else:
      errors = ['You must agree to the waiver.']
      self.render_page(errors)

application = webapp.WSGIApplication(
  [('/', MainPage)],
  debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()
